// 版权所有2021 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 这个文件将不断发展，因为我们计划混合使用模板和传递
// 查字典。

package noder

import (
	"bytes"
	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/typecheck"
	"cmd/compile/internal/types"
	"cmd/internal/src"
	"fmt"
	"strings"
)

// 用于在添加更多功能时捕捉问题
// TODO（danscales）：删除断言或替换为base.FatalfAt（）
func assert(p bool) {
	if !p {
		panic("assertion failed")
	}
}

// 模具扫描函数以获取实例化的通用函数调用，并创建
// 简单泛型函数所需的实例化。它还创造了
// 所有已完全实例化的泛型类型的实例化方法
// 已遇到或在模板制作过程中遇到的新问题
// 过程
func (g *irgen) stencil() {
	g.target.Stencils = make(map[*types.Sym]*ir.Func)

	// 实例化到目前为止我们已经看到的实例化泛型类型的方法。
	g.instantiateMethods()

	// 不要使用range（g.target.Decls）-我们还希望处理任何新的实例化
	// 在此循环期间创建的函数，以便处理泛型
	// 调用其他泛型函数的函数。
	for i := 0; i < len(g.target.Decls); i++ {
		decl := g.target.Decls[i]

		// 在非泛型函数体中查找函数实例化
		// 函数或在全局赋值中（忽略全局类型和
		// 常量声明）。
		switch decl.Op() {
		case ir.ODCLFUNC:
			if decl.Type().HasTParam() {
				// 跳过任何泛型函数
				continue
			}
			// 下面的transformCall（）取决于设置的CurFunc。
			ir.CurFunc = decl.(*ir.Func)

		case ir.OAS, ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV, ir.OASOP:
			// 这些都是各种各样的全球任务，
			// 其右侧可能包含函数
			// 实例化。

		default:
			// 顶层的其他可能操作是ODCLCONST
			// 和ODCLTYPE，它们没有任何函数
			// 实例化。
			continue
		}

		// 对于所有非泛型代码，使用
		// 泛型函数实例化。然后创建所需的
		// 实例化函数（如果尚未创建），并更改
		// 直接调用该函数。
		modified := false
		foundFuncInst := false
		ir.Visit(decl, func(n ir.Node) {
			if n.Op() == ir.OFUNCINST {
				// 我们发现一个函数实例化不是
				// 我立刻打电话来。
				foundFuncInst = true
			}
			if n.Op() != ir.OCALL || n.(*ir.CallExpr).X.Op() != ir.OFUNCINST {
				return
			}
			// 我们发现了一个使用泛型函数的函数调用
			// 实例化。
			call := n.(*ir.CallExpr)
			inst := call.X.(*ir.InstExpr)
			st := g.getInstantiationForNode(inst)
			// 将OFUNCINST替换为对的直接引用
			// 新模板功能
			call.X = st.Nname
			if inst.X.Op() == ir.OCALLPART {
				// 当我们创建一个方法的实例化时
				// 调用，我们把它变成一个函数。所以，移动
				// receiver是函数的第一个参数
				// 呼叫
				withRecv := make([]ir.Node, len(call.Args)+1)
				dot := inst.X.(*ir.SelectorExpr)
				withRecv[0] = dot.X
				copy(withRecv[1:], call.Args)
				call.Args = withRecv
			}
			// 立即转换调用，从而更改OCALL
			// 到OCALLFUNC并执行typecheckast/assignconvfn。
			transformCall(call)
			modified = true
		})

		// 如果我们在
		// 在decl上方，然后再次遍历decl的节点（使用
		// 编辑而不是访问），我们实际上在那里更改
		// OFUNINST节点到实例化函数的ONAME。
		// 编辑儿童比参观要贵，所以我们只做这件事
		// 在罕见的情况下，没有相应的
		// 呼叫
		if foundFuncInst {
			var edit func(ir.Node) ir.Node
			edit = func(x ir.Node) ir.Node {
				if x.Op() == ir.OFUNCINST {
					st := g.getInstantiationForNode(x.(*ir.InstExpr))
					return st.Nname
				}
				ir.EditChildren(x, edit)
				return x
			}
			edit(decl)
		}
		if base.Flag.W > 1 && modified {
			ir.Dump(fmt.Sprintf("\nmodified %v", decl), decl)
		}
		ir.CurFunc = nil
		// 我们可能已经看到了新的完全实例化的泛型类型
		// 实例化上述过程中所需的任何函数/方法
		// 作用如果是，请实例化这些类型的所有方法
		// （这将导致更多的函数/方法在循环中进行扫描）。
		g.instantiateMethods()
	}

}

// 实例化方法实例化所有完全实例化的方法的所有方法
// 已添加到g.instTypeList的泛型类型。
func (g *irgen) instantiateMethods() {
	for i := 0; i < len(g.instTypeList); i++ {
		typ := g.instTypeList[i]
		// 通过查找
		// 通用（未命名）名称。
		baseSym := typ.Sym().Pkg.Lookup(genericTypeName(typ.Sym()))
		baseType := baseSym.Def.(*ir.Name).Type()
		for j, m := range typ.Methods().Slice() {
			name := m.Nname.(*ir.Name)
			targs := make([]ir.Node, len(typ.RParams()))
			for k, targ := range typ.RParams() {
				targs[k] = ir.TypeNode(targ)
			}
			baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
			name.Func = g.getInstantiation(baseNname, targs, true)
		}
	}
	g.instTypeList = nil

}

// genericSym返回名为的类型的基泛型类型的名称
// 符号。它只返回通过删除
// 第一个括号（“[”）。
func genericTypeName(sym *types.Sym) string {
	return sym.Name[0:strings.Index(sym.Name, "[")]
}

// getInstantiationForNode返回函数的函数/方法实例化
// InstExpr节点inst。
func (g *irgen) getInstantiationForNode(inst *ir.InstExpr) *ir.Func {
	if meth, ok := inst.X.(*ir.SelectorExpr); ok {
		return g.getInstantiation(meth.Selection.Nname.(*ir.Name), inst.Targs, true)
	} else {
		return g.getInstantiation(inst.X.(*ir.Name), inst.Targs, false)
	}
}

// getInstantiation获取函数或方法nameNode的实例
// 使用类型参数targs。如果实例化的函数尚未
// 缓存，然后调用genericSubst来创建新的实例化。
func (g *irgen) getInstantiation(nameNode *ir.Name, targs []ir.Node, isMeth bool) *ir.Func {
	sym := makeInstName(nameNode.Sym(), targs, isMeth)
	st := g.target.Stencils[sym]
	if st == nil {
		// 如果实例化还不存在，则创建它并添加
		// 到decls列表。
		st = g.genericSubst(sym, nameNode, targs, isMeth)
		g.target.Stencils[sym] = st
		g.target.Decls = append(g.target.Decls, st)
		if base.Flag.W > 1 {
			ir.Dump(fmt.Sprintf("\nstenciled %v", st), st)
		}
	}
	return st
}

// MakeinsName为模板化泛型函数或方法生成唯一名称，
// 基于函数fy=nsym和targs的名称。它取代了任何
// 名称中的现有括号类型列表。makeInstName断言fnsym具有
// 名称中的括号当且仅当Has括号为true时。
// TODO（danscales）：稍后删除断言和has括号参数。
// None
// 声明的泛型函数的名称最初没有括号，因此有括号
// 应该是假的。由于新的
// 类型参数在接收器的通用类型中指定（例如func
// （func（v*value[T]）.set（…）{…}具有原始名称（*value[T]）.set。
// None
// 函数和函数的标准命名类似于：“genFn[int，bool]”
// 方法的“（*genType[int，bool]）.methodName”
func makeInstName(fnsym *types.Sym, targs []ir.Node, hasBrackets bool) *types.Sym {
	b := bytes.NewBufferString("")
	name := fnsym.Name
	i := strings.Index(name, "[")
	assert(hasBrackets == (i >= 0))
	if i >= 0 {
		b.WriteString(name[0:i])
	} else {
		b.WriteString(name)
	}
	b.WriteString("[")
	for i, targ := range targs {
		if i > 0 {
			b.WriteString(",")
		}
		b.WriteString(targ.Type().String())
	}
	b.WriteString("]")
	if i >= 0 {
		i2 := strings.Index(name[i:], "]")
		assert(i2 >= 0)
		b.WriteString(name[i+i2+1:])
	}
	return typecheck.Lookup(b.String())
}

// 结构，其中包含在创建
// 使用指定的类型参数实例化泛型函数。
type subster struct {
	g        *irgen
	isMethod bool     // 如果正在实例化一个方法
	newf     *ir.Func // 新模板函数的Func节点
	tparams  []*types.Field
	targs    []ir.Node
	// 从泛型函数中的名称节点到
	// 命名新模板函数中的节点。
	vars map[*ir.Name]*ir.Name
}

// genericSubst返回一个名为newsym的新函数。该函数是一个
// 类型为的namedNode指定的泛型函数或方法的实例化
// args args。对于具有泛型接收器的方法，它返回一个实例化的
// 接收器成为第一个参数的函数类型。否则
// 实例化的方法仍然需要由以后的编译器进行转换
// 阶段。
func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, targs []ir.Node, isMethod bool) *ir.Func {
	var tparams []*types.Field
	if isMethod {
		// 从方法接收器获取类型参数（跳过后
		// （在任何指针上）
		recvType := nameNode.Type().Recv().Type
		recvType = deref(recvType)
		tparams = make([]*types.Field, len(recvType.RParams()))
		for i, rparam := range recvType.RParams() {
			tparams[i] = types.NewField(src.NoXPos, nil, rparam)
		}
	} else {
		tparams = nameNode.Type().TParams().Fields().Slice()
	}
	gf := nameNode.Func
	// 实例化函数的位置与泛型函数相同
	newf := ir.NewFunc(gf.Pos())
	newf.Pragma = gf.Pragma // 将pragmas从泛型函数复制到模板化实现。
	newf.Nname = ir.NewNameAt(gf.Pos(), newsym)
	newf.Nname.Func = newf
	newf.Nname.Defn = newf
	newsym.Def = newf.Nname
	savef := ir.CurFunc
	// transformCall/transformReturn（在主体模板制作期间调用）
	// 取决于正在设置的ir.CurFunc。
	ir.CurFunc = newf

	assert(len(tparams) == len(targs))

	subst := &subster{
		g:        g,
		isMethod: isMethod,
		newf:     newf,
		tparams:  tparams,
		targs:    targs,
		vars:     make(map[*ir.Name]*ir.Name),
	}

	newf.Dcl = make([]*ir.Name, len(gf.Dcl))
	for i, n := range gf.Dcl {
		newf.Dcl[i] = subst.node(n).(*ir.Name)
	}

	// 丑陋：我们必须将参数/结果的名称节点插入到
	// 函数类型。当前函数类型未设置Nname字段，
	// 因为它是通过从types2类型转换而来的。
	oldt := nameNode.Type()
	// 我们还将泛型方法类型转换为相应的
	// 实例化的函数类型，其中接收器是第一个参数。
	newt := types.NewSignature(oldt.Pkg(), nil, nil,
		subst.fields(ir.PPARAM, append(oldt.Recvs().FieldSlice(), oldt.Params().FieldSlice()...), newf.Dcl),
		subst.fields(ir.PPARAMOUT, oldt.Results().FieldSlice(), newf.Dcl))

	newf.Nname.SetType(newt)
	ir.MarkFunc(newf.Nname)
	newf.SetTypecheck(1)
	newf.Nname.SetTypecheck(1)

	// 在替换主体之前，请确保设置了newf的名称/类型。
	newf.Body = subst.list(gf.Body)
	ir.CurFunc = savef

	return newf
}

// 节点类似于DeepCopy（），但会创建不同的ONAME节点，也会下降
// 关闭。它用类型参数替换所有新类型中的类型参数
// 节点。
func (subst *subster) node(n ir.Node) ir.Node {
	// 使用闭包捕获ir.EditChildren参数所需的所有状态。
	var edit func(ir.Node) ir.Node
	edit = func(x ir.Node) ir.Node {
		switch x.Op() {
		case ir.OTYPE:
			return ir.TypeNode(subst.typ(x.Type()))

		case ir.ONAME:
			name := x.(*ir.Name)
			if v := subst.vars[name]; v != nil {
				return v
			}
			m := ir.NewNameAt(name.Pos(), name.Sym())
			if name.IsClosureVar() {
				m.SetIsClosureVar(true)
			}
			t := x.Type()
			if t == nil {
				assert(name.BuiltinOp != 0)
			} else {
				newt := subst.typ(t)
				m.SetType(newt)
			}
			m.BuiltinOp = name.BuiltinOp
			m.Curfn = subst.newf
			m.Class = name.Class
			m.Func = name.Func
			subst.vars[name] = m
			m.SetTypecheck(1)
			return m
		case ir.OLITERAL, ir.ONIL:
			if x.Sym() != nil {
				return x
			}
		}
		m := ir.Copy(x)
		if _, isExpr := m.(ir.Expr); isExpr {
			t := x.Type()
			if t == nil {
				// 只有当这是一个没有
				// 返回值，所以允许这样做，否则给出
				// 一个错误。
				_, isCallExpr := m.(*ir.CallExpr)
				_, isStructKeyExpr := m.(*ir.StructKeyExpr)
				if !isCallExpr && !isStructKeyExpr && x.Op() != ir.OPANIC &&
					x.Op() != ir.OCLOSE {
					base.Fatalf(fmt.Sprintf("Nil type for %v", x))
				}
			} else if x.Op() != ir.OCLOSURE {
				m.SetType(subst.typ(x.Type()))
			}
		}
		ir.EditChildren(m, edit)

		if x.Typecheck() == 3 {
			// 这些节点的转换延迟到
			// 他们的实例化类型是已知的。
			m.SetTypecheck(1)
			if typecheck.IsCmp(x.Op()) {
				transformCompare(m.(*ir.BinaryExpr))
			} else {
				switch x.Op() {
				case ir.OSLICE, ir.OSLICE3:
					transformSlice(m.(*ir.SliceExpr))

				case ir.OADD:
					m = transformAdd(m.(*ir.BinaryExpr))

				case ir.OINDEX:
					transformIndex(m.(*ir.IndexExpr))

				case ir.OAS2:
					as2 := m.(*ir.AssignListStmt)
					transformAssign(as2, as2.Lhs, as2.Rhs)

				case ir.OAS:
					as := m.(*ir.AssignStmt)
					lhs, rhs := []ir.Node{as.X}, []ir.Node{as.Y}
					transformAssign(as, lhs, rhs)

				case ir.OASOP:
					as := m.(*ir.AssignOpStmt)
					transformCheckAssign(as, as.X)

				case ir.ORETURN:
					transformReturn(m.(*ir.ReturnStmt))

				case ir.OSEND:
					transformSend(m.(*ir.SendStmt))

				default:
					base.Fatalf("Unexpected node with Typecheck() == 3")
				}
			}
		}

		switch x.Op() {
		case ir.OLITERAL:
			t := m.Type()
			if t != x.Type() {
				// types2会给我们一个T型常数，
				// 如果一个非类型化常量与另一个常量一起使用
				// T类型的操作数（以可证明正确的方式）。
				// 当我们在类型args中替换时
				// 模版印刷，我们现在知道了
				// 常数然后，我们可能需要更改
				// BasicLit.val是正确的类型（例如。
				// 将int64Val常量转换为floatVal
				// 常数）。
				m.SetType(types.UntypedInt) // 使用任何非类型化类型使DefaultLit正常工作
				m = typecheck.DefaultLit(m, t)
			}

		case ir.OXDOT:
			// 通过类型参数进行的方法值/调用将被删除
			// 左边是一个牛角点。当我们在制版过程中看到这一点时，
			// 完成转换，现在我们有了
			// 实例化的接收器类型。我们现在必须这样做，
			// 由于访问/选择的方法为真实
			// 类型与类型的选择非常不同
			// 帕拉姆。m将被转换为OCALLPART节点。信息技术
			// 将转换为ODOTMETH或ODOTINTER节点，如果
			// 在下面的OCALL案例中，我们发现方法值
			// 实际上是叫。
			transformDot(m.(*ir.SelectorExpr), false)
			m.SetTypecheck(1)

		case ir.OCALL:
			call := m.(*ir.CallExpr)
			switch call.X.Op() {
			case ir.OTYPE:
				// 转换转换，现在我们知道了
				// 类型参数。
				m = transformConvCall(m.(*ir.CallExpr))

			case ir.OCALLPART:
				// 重做OXDOT的转换，现在我们
				// 知道正在调用的方法值。然后
				// 转换呼叫。
				call.X.(*ir.SelectorExpr).SetOp(ir.OXDOT)
				transformDot(call.X.(*ir.SelectorExpr), true)
				transformCall(call)

			case ir.ODOT, ir.ODOTPTR:
				// 通用接收器的OXDOT被解析为
				// 对具有函数的字段的访问
				// 价值现在将调用转换为该函数
				// OXDOT已经解决了。
				transformCall(call)

			case ir.ONAME:
				name := call.X.Name()
				if name.BuiltinOp != ir.OXXX {
					switch name.BuiltinOp {
					case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OLEN, ir.OCAP, ir.OAPPEND:
						// 现在，我们需要改造这些内置组件
						// 知道args的类型。
						m = transformBuiltin(call)
					default:
						base.FatalfAt(call.Pos(), "Unexpected builtin op")
					}
				} else {
					// 这是函数值为
					// 类型参数（通过
					// 结构约束），现在已解决。
					transformCall(call)
				}

			case ir.OCLOSURE:
				transformCall(call)

			case ir.OFUNCINST:
				// 带有OFUNINST的调用将被转换
				// 在模具（）中创建并附加
				// 要调用的实例化。

			default:
				base.FatalfAt(call.Pos(), fmt.Sprintf("Unexpected op with CALL during stenciling: %v", call.X.Op()))
			}

		case ir.OCLOSURE:
			x := x.(*ir.ClosureExpr)
			// 需要复制x.Func.Nname、x.Func.Dcl、x.Func.ClosureVars和
			// x、 职能机构。
			oldfn := x.Func
			newfn := ir.NewFunc(oldfn.Pos())
			if oldfn.ClosureCalled() {
				newfn.SetClosureCalled(true)
			}
			newfn.SetIsHiddenClosure(true)
			m.(*ir.ClosureExpr).Func = newfn
			// 闭包名称可以已经有括号（如果派生的话）
			// 从泛型方法
			newsym := makeInstName(oldfn.Nname.Sym(), subst.targs, subst.isMethod)
			newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym)
			newfn.Nname.Func = newfn
			newfn.Nname.Defn = newfn
			ir.MarkFunc(newfn.Nname)
			newfn.OClosure = m.(*ir.ClosureExpr)

			saveNewf := subst.newf
			ir.CurFunc = newfn
			subst.newf = newfn
			newfn.Dcl = subst.namelist(oldfn.Dcl)
			newfn.ClosureVars = subst.namelist(oldfn.ClosureVars)

			typed(subst.typ(oldfn.Nname.Type()), newfn.Nname)
			typed(newfn.Nname.Type(), m)
			newfn.SetTypecheck(1)

			// 在执行正文之前，请确保设置了闭包函数的类型。
			newfn.Body = subst.list(oldfn.Body)
			subst.newf = saveNewf
			ir.CurFunc = saveNewf

			subst.g.target.Decls = append(subst.g.target.Decls, newfn)
		}
		return m
	}

	return edit(n)
}

func (subst *subster) namelist(l []*ir.Name) []*ir.Name {
	s := make([]*ir.Name, len(l))
	for i, n := range l {
		s[i] = subst.node(n).(*ir.Name)
		if n.Defn != nil {
			s[i].Defn = subst.node(n.Defn)
		}
		if n.Outer != nil {
			s[i].Outer = subst.node(n.Outer).(*ir.Name)
		}
	}
	return s
}

func (subst *subster) list(l []ir.Node) []ir.Node {
	s := make([]ir.Node, len(l))
	for i, n := range l {
		s[i] = subst.node(n)
	}
	return s
}

// tstruct在结构类型的字段类型中替换类型参数。对于
// 如果设置了Nname，则tstruct还会使用
// subst.vars，如果Nname在subst.vars中。始终强制创建一个新的
// （顶级）结构，无论是否随类型或
// 结构字段的名称，将force设置为true。
func (subst *subster) tstruct(t *types.Type, force bool) *types.Type {
	if t.NumFields() == 0 {
		if t.HasTParam() {
			// 对于空结构，我们需要返回一个新类型，
			// 因为它现在可以完全实例化（HasTParam）
			// 变为假）。
			return types.NewStruct(t.Pkg(), nil)
		}
		return t
	}
	var newfields []*types.Field
	if force {
		newfields = make([]*types.Field, t.NumFields())
	}
	for i, f := range t.Fields().Slice() {
		t2 := subst.typ(f.Type)
		if (t2 != f.Type || f.Nname != nil) && newfields == nil {
			newfields = make([]*types.Field, t.NumFields())
			for j := 0; j < i; j++ {
				newfields[j] = t.Field(j)
			}
		}
		if newfields != nil {
			// TODO（danscales）：确保这在现场有效
			// 嵌入类型的名称（应保留
			// 类型参数，而不是实例化的类型）。
			newfields[i] = types.NewField(f.Pos, f.Sym, t2)
			if f.Nname != nil {
				// f、 如果是，则Nname可能不在subst.vars[]中
				// 函数名或函数实例化类型
				// 我们正在翻译的
				v := subst.vars[f.Nname.(*ir.Name)]
				// 注意不要在Nname中输入零var，
				// 因为Nname是一个接口，所以它将是一个
				// 非零接口。
				if v != nil {
					newfields[i].Nname = v
				}
			}
		}
	}
	if newfields != nil {
		return types.NewStruct(t.Pkg(), newfields)
	}
	return t

}

// 着色程序在接口类型的方法类型中替换类型参数。
func (subst *subster) tinter(t *types.Type) *types.Type {
	if t.Methods().Len() == 0 {
		return t
	}
	var newfields []*types.Field
	for i, f := range t.Methods().Slice() {
		t2 := subst.typ(f.Type)
		if (t2 != f.Type || f.Nname != nil) && newfields == nil {
			newfields = make([]*types.Field, t.Methods().Len())
			for j := 0; j < i; j++ {
				newfields[j] = t.Methods().Index(j)
			}
		}
		if newfields != nil {
			newfields[i] = types.NewField(f.Pos, f.Sym, t2)
		}
	}
	if newfields != nil {
		return types.NewInterface(t.Pkg(), newfields)
	}
	return t
}

// instTypeName根据实例的名称为实例化的类型创建名称
// 泛型类型和类型args
func instTypeName(name string, targs []*types.Type) string {
	b := bytes.NewBufferString(name)
	b.WriteByte('[')
	for i, targ := range targs {
		if i > 0 {
			b.WriteByte(',')
		}
		b.WriteString(targ.String())
	}
	b.WriteByte(']')
	return b.String()
}

// typ计算通过将t中的任何类型参数替换为
// subst中对应的类型参数。如果t不包含类型参数，则
// 结果为t；否则，结果将是一个新类型。它处理递归类型
// 通过使用TFORW类型并通过sym.Def查找部分或完全创建的类型。
func (subst *subster) typ(t *types.Type) *types.Type {
	if !t.HasTParam() && t.Kind() != types.TFUNC {
		// 注意：不管怎样，都需要复制函数类型，因为
		// 闭包类型可能包含需要
		// 被复制。见#45738。
		return t
	}

	if t.Kind() == types.TTYPEPARAM {
		for i, tp := range subst.tparams {
			if tp.Type == t {
				return subst.targs[i].Type()
			}
		}
		// 如果t是一个简单的typeparam t，则t具有名称/符号“t”
		// 和t.底层（）==t。
		// None
		// 但是，请考虑类型定义：“类型p[t任意] t'。我们
		// 可能会使用这个定义，这样我们就可以有一个T类型的变体
		// 我们可以添加新的方法。假设t是对
		// P[T]。t的名称为“P[t]”，但它的类型为TTYPEPARAM，
		// 因为P[T]被定义为T。如果我们看一下T.underlined（），它
		// 是不同的，因为t.undernative（）的名称是“t”，而不是
		// 而不是“P[T]”。但是，t.underground（）的类型也是TTYPEPARAM。
		// 在本例中，我们在
		// 案件陈述如下。
		if t.Underlying() == t {
			// t是一个简单的typeparam，与tparam中的任何内容都不匹配
			return t
		}
		// t是一个更复杂的typeparam（例如P[t]，如上所述，其
		// 定义就是（T）。
		assert(t.Sym() != nil)
	}

	var newsym *types.Sym
	var neededTargs []*types.Type
	var forw *types.Type

	if t.Sym() != nil {
		// 根据转换此类型的类型参数
		// subst的tparam/targs映射。
		neededTargs = make([]*types.Type, len(t.RParams()))
		for i, rparam := range t.RParams() {
			neededTargs[i] = subst.typ(rparam)
		}
		// 对于命名（定义）类型，我们必须更改
		// 也要打字。我们先这样做，这样我们就可以在
		// 在此替换或其他过程中已看到此类型
		// 定义/替换。
		genName := genericTypeName(t.Sym())
		newsym = t.Sym().Pkg.Lookup(instTypeName(genName, neededTargs))
		if newsym.Def != nil {
			// 我们已经创建了这个实例化的定义类型。
			return newsym.Def.Type()
		}

		// 为了处理递归泛型类型，请创建一个TFORW
		// 最初键入并设置其sym的Def字段，以便
		// 如果此类型在该类型中递归出现，则找到。
		forw = newIncompleteNamedType(t.Pos(), newsym)
		// println（“通过sub创建新类型”，newsym.Name，forw.HasTParam（））
		forw.SetRParams(neededTargs)
	}

	var newt *types.Type

	switch t.Kind() {
	case types.TTYPEPARAM:
		if t.Sym() == newsym {
			// 替换并没有改变类型。
			return t
		}
		// 替换基础typeparam（例如P[T]中的T），请参见
		// 上面描述类型P[T]的示例）。
		newt = subst.typ(t.Underlying())
		assert(newt != t)

	case types.TARRAY:
		elem := t.Elem()
		newelem := subst.typ(elem)
		if newelem != elem {
			newt = types.NewArray(newelem, t.NumElem())
		}

	case types.TPTR:
		elem := t.Elem()
		newelem := subst.typ(elem)
		if newelem != elem {
			newt = types.NewPtr(newelem)
		}

	case types.TSLICE:
		elem := t.Elem()
		newelem := subst.typ(elem)
		if newelem != elem {
			newt = types.NewSlice(newelem)
		}

	case types.TSTRUCT:
		newt = subst.tstruct(t, false)
		if newt == t {
			newt = nil
		}

	case types.TFUNC:
		newrecvs := subst.tstruct(t.Recvs(), false)
		newparams := subst.tstruct(t.Params(), false)
		newresults := subst.tstruct(t.Results(), false)
		if newrecvs != t.Recvs() || newparams != t.Params() || newresults != t.Results() {
			// 如果任何类型已更改，则
			// 必须复制recv、参数和结果的，因为它们具有
			// 相关的偏移字段，因此必须具有
			// 每个新签名的独立副本。
			var newrecv *types.Field
			if newrecvs.NumFields() > 0 {
				if newrecvs == t.Recvs() {
					newrecvs = subst.tstruct(t.Recvs(), true)
				}
				newrecv = newrecvs.Field(0)
			}
			if newparams == t.Params() {
				newparams = subst.tstruct(t.Params(), true)
			}
			if newresults == t.Results() {
				newresults = subst.tstruct(t.Results(), true)
			}
			newt = types.NewSignature(t.Pkg(), newrecv, t.TParams().FieldSlice(), newparams.FieldSlice(), newresults.FieldSlice())
		}

	case types.TINTER:
		newt = subst.tinter(t)
		if newt == t {
			newt = nil
		}

	case types.TMAP:
		newkey := subst.typ(t.Key())
		newval := subst.typ(t.Elem())
		if newkey != t.Key() || newval != t.Elem() {
			newt = types.NewMap(newkey, newval)
		}

	case types.TCHAN:
		elem := t.Elem()
		newelem := subst.typ(elem)
		if newelem != elem {
			newt = types.NewChan(newelem, t.ChanDir())
			if !newt.HasTParam() {
				// 托多（丹斯凯尔斯）：不知道我为什么要这么做
				// 仅适用于频道。。。。。
				types.CheckSize(newt)
			}
		}
	}
	if newt == nil {
		// 即使类型中有typeparams，也可能没有
		// 如果这是函数调用的函数类型（将
		// 在函数实例化中有自己的tparams/targs）。
		return t
	}

	if t.Sym() == nil {
		// 没有命名类型，因此没有转发类型，并且
		// 没有可替代的方法。
		assert(t.Methods().Len() == 0)
		return newt
	}

	forw.SetUnderlying(newt)
	newt = forw

	if t.Kind() != types.TINTER && t.Methods().Len() > 0 {
		// 填写新类型的方法信息。
		var newfields []*types.Field
		newfields = make([]*types.Field, t.Methods().Len())
		for i, f := range t.Methods().Slice() {
			t2 := subst.typ(f.Type)
			oldsym := f.Nname.Sym()
			newsym := makeInstName(oldsym, subst.targs, true)
			var nname *ir.Name
			if newsym.Def != nil {
				nname = newsym.Def.(*ir.Name)
			} else {
				nname = ir.NewNameAt(f.Pos, newsym)
				nname.SetType(t2)
				newsym.Def = nname
			}
			newfields[i] = types.NewField(f.Pos, f.Sym, t2)
			newfields[i].Nname = nname
		}
		newt.Methods().Set(newfields)
		if !newt.HasTParam() {
			// 为新的完全实例化类型生成所有方法。
			subst.g.instTypeList = append(subst.g.instTypeList, newt)
		}
	}
	return newt
}

// fields为类型签名中的字段节点设置Nname字段，基于
// 在dcl中对应的输入/输出参数上。这取决于进进出出
// 参数在dcl中处于有序状态。
func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir.Name) []*types.Field {
	// 在dcl中查找类声明的起始索引（或
	// PPARAM或PPARAMOUT）。
	var i int
	for i = range dcl {
		if dcl[i].Class == class {
			break
		}
	}

	// 创建作为oldfields节点副本的newfields节点，但
	// 替换任何类型参数，并将Nname设置为中的节点
	// 对应PPARAM或PPARAMOUT的Dcl。
	newfields := make([]*types.Field, len(oldfields))
	for j := range oldfields {
		newfields[j] = oldfields[j].Copy()
		newfields[j].Type = subst.typ(oldfields[j].Type)
		// 如果名称为，则dcl中将缺少参数字段
		// 未指定或指定为“\uu1”。因此，我们比较dcl sym
		// 使用字段sym。如果不匹配，则此dcl（如果存在
		// 左一项）必须应用于后面的字段。
		if i < len(dcl) && dcl[i].Sym() == oldfields[j].Sym {
			newfields[j].Nname = dcl[i]
			i++
		}
	}
	return newfields
}

// 如果是指针类型，则defer执行类型为t的单个defer。
func deref(t *types.Type) *types.Type {
	if t.IsPtr() {
		return t.Elem()
	}
	return t
}

// NewUncompleteNamedType返回一个由sym指定名称的TFORW类型t，例如
// t.nod和sym.Def设置正确。
func newIncompleteNamedType(pos src.XPos, sym *types.Sym) *types.Type {
	name := ir.NewDeclNameAt(pos, ir.OTYPE, sym)
	forw := types.NewNamed(name)
	name.SetType(forw)
	sym.Def = name
	return forw
}
